/*************************************************************************
** Copyright (C) 2014  Mario Marquez <maqzma@gmail.com>.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*************************************************************************/

#ifndef TIME_H
#define TIME_H

#include <functional>
#include <atomic>

class Timer;

/**
 * Reloj.
 *
 * Ejecuta la funcion tick cada
 * vez que transcurre un segundo.
 *
 * Solo maneja segundos, minutos y horas.
 *
 * Iniciar un reloj ya iniciado resulta
 * en una operacion nula, no hace nada.
 * Lo mismo al detener un reloj.
 *
 * Por motivos de seguridad es imposible
 * modificar la funcion Tick mientras
 * el reloj esta encendido.
 */
class Time
{
public:
    typedef std::function<void(void)> Tick;

    Time(const Tick &tick = nullptr);
    ~Time();

    /**
     * Inicia el conteo.
     */
    void start();

    /**
     * Detiene el conteo.
     */
    void pause();

    /**
     * Detiene y reinicia el conteo.
     * @note Pero no lo inicia!
     */
    void restart();

    bool counting();

    /**
     * Obtenemo los segundos transcurridos.
     */
    unsigned int seconds() const;

    /**
     * Obtenemo los minutos transcurridos.
     */
    unsigned int minutes() const;

    /**
     * Obtenemo los horas transcurridas.
     */
    unsigned int hours() const;

    void setTick(const Tick &tick);
    const Tick &tick();

    Time(const Time &) = delete;
    Time &operator = (const Time &) = delete;

private:
    std::atomic_uint _seconds;
    std::atomic_uint _minutes;
    std::atomic_uint _hours;

    Timer *_timer;
    Tick _tick = nullptr;

    /**
     * Incrementa los segundos, si sobre
     * pasan de 60, aumenta los minutos,
     * si sobre pasan los 60, aumenta las
     * horas. Reinicia los segundos y los
     * minutos en caso de sobrepasar los 60.
     *
     * Ejecuta la funcion tick.
     *
     * Ejecutada al pasar un segundo.
     */
    void _ptick();
};

#endif // TIME_H
